#ifndef _MODESTO_H_
#define _MODESTO_H_

#include "../definitions.h"
#include "events.h"
#include "connection.h"
#include "command.h"
#include "worker.h"
#include "mutex.h"
#include "user.h"
#include "channel.h"
#include "server.h"

void debugcommand(RawCmd cmd);

class Modesto : public IRCEvents
{
protected:
	enum MODESTO_STATUS
	{
		STARTING,
		RUNNING,
		STOPPED
	};

	ServerList		servers;
	ChannelList		channels;
	UserList			users;

	Worker			*listener;
	CommandQueue		*queue;
	
	MODESTO_STATUS		status;
	int				connections;
	
	FD_SET			readableSockets;
	FD_SET			writableSockets;

public:
	// Initialize an instance of modesto with no configuration values.
	Modesto();

	// Initialize an instance of modesto with configuration values.
	Modesto(std::string configFile);

	// Destroy this instance of the modesto bot.
	~Modesto();

	// Connect to all the servers
	bool connect();

	// Connect to a specific server.
	bool addConnection(ServerInfo info);

	// Send a message to the server.
	void send(Server *server, std::string message);

	// Send a message to a specific channel.
	void send(Server *server, Channel *channel, std::string message);

	// Send a message to a specific user.
	void send(Server *server, User *user, std::string message);

	// Receive a message from a server, and add it to the queue.
	void receive();
	
	// Open a new thread that will listen and queue all received messages.
	void startListening();

	// Listens for incoming commands, and add them to the queue.
	static DWORD listen(LPVOID *);

	// Check whether the bot is still running.
	bool isRunning();

	// Retrieve the queue of messages.
	Queue fetchQueue(); 

	// Execute a command.
	bool executeCommand(RawCmd cmd);

	// Load the modules into memory.
	bool loadModules();

	// Unload the modules from memory.
	void unloadModules();

	// Terminate modesto and handle garbage collection
	void terminate();

	void onConnect(Server *server);
	void onDisconnect(Server *server);
	void onJoin(Server *server, Channel *channel);
	void onJoin(Server *server, Channel *channel, User *user);
	void onPart(Server *server, Channel *channel, User *user);
	void onNotice(Server *server, std::string notice);
	void onMessage(Server *server, User *user, std::vector<std::string> params);
	void onMessage(Server *server, Channel *channel, User *user, std::vector<std::string> params);
	void onNick(Server *server, User *user, std::string nick);

protected:

	// Update the list of readable and writable sockets.
	int availableSockets();

	// Adds a user to the list.
	void userQuit(Server *server, User *user);

	// Remove a user from the list.
	void userJoinChannel(Channel *channel, User *user);
};

#endif